Конструктор като
оператор конвертор
Съвкупността от едно аргументни конструктори за
клас като SmallInt дефинира набор от неявни конвертори, преобразуващи
не-SmallInt типове в обекти от тип SmallInt. Стандартните конвертори, ако са
необходими, се прилагат над типовете преди извикването на
конструктора.
Конструктор, който получава един аргумент като
SmallInt(int), служи като оператор за преобразуване между типа на аргумента и
класа. SmallInt(int), например, преобразува цели стойности в обекти
на
SmallInt.extern f( SmallInt );
int i; // need to convert i into a
SmallInt
f( i ); // SmallInt(int) accmplishes this
При обръщението f(
i ), i се преобразува в обект на SmallInt чрез извикване на SmallInt(int).
Компилаторът конструира временен обект на SmallInt и го изпраща на
f().
{SmallInt temp = SmallInt(i);
f(temp);} // a temporary SmallInt
Object is created
Фигурните скоби, употребени в примера, показват
продължителността на периода на съществуване на генерирания временен обект на
SmallInt.
Ако е необходимо преди извикването на SmallInt(int) се прилага
стандартен конвертор. Например,
double d;f( d );
става
{//
warning: narrowing conversion
SmallInt temp = SmallInt( (int)d
);
f(temp);}
Извикването на оператор конвертор се извършва само ако не
са възможни други преобразувания. Ако f() беше презаредима функция, както е в
следващия пример, SmallInt(int) нямаше да бъде извикана.
f( SmallInt
);
f( double );
int ival;// matches f(double) by standard conversion
f(
ival );
Аргументът може да бъде и от друг, дефиниран от потребителя клас.
Например,
class Token
{public: // ... public
membersprivate:
SmallInt tok;// ... rest of Token members};
// create a
Smallint object from a Token
SmallInt::SmallInt( Token& t ) { /* ... */
}
extern f( Smallint& );
Token curTok;
main()
{{ // invoke
SmallInt( Token& );
f( curTok );}
Оператори
конвертори
Операторите за конвертиране, които са специални
представители на член функциите на един клас, определят неявното преобразуване
на обекти на класа в някакви други типове. SmallInt, например, може да дефинира
преобразуване на обект на SmallInt в стойност от тип unsigned
int:
SmallInt::Operator unsigned int(){return( (unsigned)value
);}
Класът Token, дефиниран по-нататък в текста, може да дефинира много
оператори конвертори:
#include "SmallInt.h"
class
Token{public:
Token( char *nm, int v1 ): val( v1 ), name( nm ) {}
operator
SmallInt() { return val; }
operator char*() { return name; }
operator
int() { return val; }// .. rest of public membersprivate:
SmallInt
val;
char *name;};
Забележете, че операторите конвертори на Token за
SmallInt и int са еднакви. SmallInt::Operator int() е приложен неявно над обекта
val на SmallInt в Token::Operator int(). Например,
#include
"Token.h"
void f( int i )
{ cout << "nf(int) : " <<
i;}
Token t1( "integer constant", 127 );
main()
{ Token t2( "friend",
255 );
f( t1 ); // t1.operator int()f( t2 ); // t2.operator
int()}
Когато бъде компилирана и изпълнена тази малка програма дава
следния резултат:
f(int) : 127f(int) : 255
Един оператор конвертор
има следния общ вид:
operator <type> ();
където <type>
се замества с определен вграден, произлязъл или класов тип. (Операторите
конвертори на масиви или функции не са допустими). Операторите конвертори трябва
да бъдат член функции. Те не трябва да определят тип за връщане нито могат да
имат списък от аргументи. Всяка от следните декларации, например, е
недопустима:
operator int( SmallInt& ); // error:
nonmember class
SmallInt{public:int operator int(); // error:
return type operator int( int
); // error:
argument list ...};
Програмистът може явно да извика
оператор конвертор като използува една от двете форми на записа за
преобразуване. Например,
#include "Token.h"
Token tok( "function", 78
);// function cast notation:
operator SmallInt() SmallInt tokVal = SmallInt(
tok );// type cast notation:
operator char*()char *tokString = (char
*)tok;
Ако съществува обект на клас, който не е от подходящ тип, и е
дефиниран оператор конвертор той ще бъде неявно приложен от компилатора.
Например,
#include "Token.h"
extern void f( char *);
Token tok(
"enumeration", 8 );
enum { ENUM }; // token constant
main() {
f(
tok ); // tok.operator
char*();// explicit functional cast notation
switch
( int(tok) ) // tok.operator int() {case ENUM:{
// tok.operator
SmallInt();
SmallInt si = tok;// ...}
}}
Да допуснем, че желаният
тип не съответствува точно на никой от операторите конвертори. Ще бъде ли
извикан оператор конвертор?
да, ако желаният тип може да бъде получен
чрез стандартно преобразуване. Например,
extern void f( double
);
Token tok( "constant", 44 );// tok.operator
int() invoked// int ==>
double by standard conversionf( tok );
не, ако желаният тип може да бъде
получен чрез прилагане на втори оператор конвертор, дефиниран от потребителя
върху резултата от първи, дефиниран от потребителя, оператор конвертор. (Ето
защо Token дефинира както operator SmallInt() така и operator int()). Например,
ако Token не предлага представител на operator int() следното обръщение би било
недопустимо:
extern void f(int);
Token tok( "pointer", 37 );//
without
Token::Operator int() defined,// this call will generate a
compile-time error
f( tok );
Ако Token::Operator int() не е дефиниран,
преобразуването на tok към типа int ще изисква извикването на два оператора
конвертори, дефинирани от потребителя.
Token::Operator
SmallInt();
ще преобразува tok в обект на
SmallInt.
SmallInt::Operator int();
ще завърши преобразуването до
типа int.
Според правилото, обаче, могат да бъдат прилагани оператори
конвертори, дефинирани от потребителя, само от едно ниво. Ако Token::Operator
int() не е дефиниран, обръщението f(tok), изискващо аргумент от тип int,
предизвиква грешка по време на компилация поради нарушение на
типовете.